<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>网页电子钢琴</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Arial', sans-serif;
            background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            padding: 20px;
        }
        
        .piano-container {
            text-align: center;
            background: rgba(255, 255, 255, 0.1);
            padding: 40px;
            border-radius: 20px;
            backdrop-filter: blur(10px);
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
        }
        
        h1 {
            color: white;
            margin-bottom: 30px;
            font-size: 2.5em;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
        }
        
        .piano {
            display: inline-block;
            background: #2c3e50;
            padding: 30px 20px 20px;
            border-radius: 15px;
            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
            position: relative;
        }
        
        .keys-container {
            display: flex;
            position: relative;
            height: 250px;
        }
        
        .white-key {
            width: 60px;
            height: 250px;
            background: linear-gradient(to bottom, #ffffff 0%, #f0f0f0 100%);
            border: 2px solid #333;
            border-radius: 0 0 8px 8px;
            margin: 0 2px;
            cursor: pointer;
            position: relative;
            transition: all 0.1s;
            box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
        }
        
        .white-key:hover {
            background: linear-gradient(to bottom, #f0f0f0 0%, #e0e0e0 100%);
        }
        
        .white-key:active,
        .white-key.active {
            background: linear-gradient(to bottom, #e0e0e0 0%, #d0d0d0 100%);
            transform: translateY(2px);
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
        }
        
        .black-key {
            width: 40px;
            height: 150px;
            background: linear-gradient(to bottom, #2c3e50 0%, #1a252f 100%);
            border: 2px solid #000;
            border-radius: 0 0 5px 5px;
            cursor: pointer;
            position: absolute;
            z-index: 2;
            transition: all 0.1s;
            box-shadow: 0 5px 10px rgba(0, 0, 0, 0.5);
        }
        
        .black-key:hover {
            background: linear-gradient(to bottom, #34495e 0%, #2c3e50 100%);
        }
        
        .black-key:active,
        .black-key.active {
            background: linear-gradient(to bottom, #1a252f 0%, #0d1419 100%);
            transform: translateY(2px);
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
        }
        
        .key-label {
            position: absolute;
            bottom: 10px;
            left: 50%;
            transform: translateX(-50%);
            font-size: 12px;
            color: #666;
            font-weight: bold;
        }
        
        .black-key .key-label {
            color: #aaa;
            bottom: 5px;
            font-size: 10px;
        }
        
        .note-name {
            position: absolute;
            bottom: 35px;
            left: 50%;
            transform: translateX(-50%);
            font-size: 14px;
            color: #333;
            font-weight: bold;
        }
        
        .black-key .note-name {
            color: #ccc;
            bottom: 25px;
            font-size: 12px;
        }
        
        .controls {
            margin-top: 30px;
            display: flex;
            gap: 15px;
            justify-content: center;
            flex-wrap: wrap;
        }
        
        button {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            padding: 12px 25px;
            font-size: 1em;
            border-radius: 25px;
            cursor: pointer;
            transition: all 0.3s;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
        }
        
        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
        }
        
        button:active {
            transform: translateY(0);
        }
        
        .song-select {
            padding: 10px 20px;
            font-size: 1em;
            border-radius: 20px;
            border: 2px solid #667eea;
            background: white;
            cursor: pointer;
            outline: none;
        }
        
        .instructions {
            color: white;
            margin-top: 20px;
            font-size: 0.9em;
            line-height: 1.6;
            max-width: 600px;
            margin-left: auto;
            margin-right: auto;
        }
        
        .volume-control {
            display: flex;
            align-items: center;
            gap: 10px;
            color: white;
            margin-top: 20px;
            justify-content: center;
        }
        
        .volume-slider {
            width: 200px;
            height: 6px;
            border-radius: 3px;
            background: rgba(255, 255, 255, 0.3);
            outline: none;
            cursor: pointer;
        }
        
        .recording-indicator {
            display: none;
            color: #ff6b6b;
            font-weight: bold;
            margin-top: 10px;
            animation: blink 1s infinite;
        }
        
        @keyframes blink {
            0%,
            50% {
                opacity: 1;
            }
            51%,
            100% {
                opacity: 0.3;
            }
        }
        
        .recording-indicator.active {
            display: block;
        }
    </style>
</head>

<body>
    <div class="piano-container">
        <h1>🎹 网页电子钢琴</h1>

        <div class="piano">
            <div class="keys-container" id="keysContainer">
                <!-- 钢琴键将通过 JavaScript 动态生成 -->
            </div>
        </div>

        <div class="controls">
            <select class="song-select" id="songSelect">
                <option value="">选择曲目</option>
                <option value="twinkle">小星星</option>
                <option value="birthday">生日快乐</option>
                <option value="jingle">铃儿响叮当</option>
                <option value="ode">欢乐颂</option>
            </select>
            <button id="playBtn">▶ 播放</button>
            <button id="stopBtn">⏹ 停止</button>
            <button id="recordBtn">⏺ 录制</button>
            <button id="playbackBtn" disabled>▶ 回放</button>
        </div>

        <div class="volume-control">
            <span>🔊 音量:</span>
            <input type="range" class="volume-slider" id="volumeSlider" min="0" max="100" value="50">
            <span id="volumeValue">50%</span>
        </div>

        <div class="recording-indicator" id="recordingIndicator">● 正在录制...</div>

        <div class="instructions">
            💡 <strong>使用说明：</strong><br> • 点击琴键或使用键盘按键弹奏（A-K 对应白键，W/E/T/Y/U 对应黑键）<br> • 选择曲目后点击"播放"可自动演奏<br> • 点击"录制"开始录制，再次点击停止，然后可以"回放"你的演奏
        </div>
    </div>

    <script>
        // 音频上下文
        const audioContext = new(window.AudioContext || window.webkitAudioContext)();
        let masterVolume = 0.5;

        // 音符频率映射（C4-C6）
        const noteFrequencies = {
            'C4': 261.63,
            'C#4': 277.18,
            'D4': 293.66,
            'D#4': 311.13,
            'E4': 329.63,
            'F4': 349.23,
            'F#4': 369.99,
            'G4': 392.00,
            'G#4': 415.30,
            'A4': 440.00,
            'A#4': 466.16,
            'B4': 493.88,
            'C5': 523.25,
            'C#5': 554.37,
            'D5': 587.33,
            'D#5': 622.25,
            'E5': 659.25,
            'F5': 698.46,
            'F#5': 739.99,
            'G5': 783.99,
            'G#5': 830.61,
            'A5': 880.00,
            'A#5': 932.33,
            'B5': 987.77,
            'C6': 1046.50
        };

        // 键盘映射
        const keyboardMap = {
            'a': 'C4',
            'w': 'C#4',
            's': 'D4',
            'e': 'D#4',
            'd': 'E4',
            'f': 'F4',
            't': 'F#4',
            'g': 'G4',
            'y': 'G#4',
            'h': 'A4',
            'u': 'A#4',
            'j': 'B4',
            'k': 'C5',
            'o': 'C#5',
            'l': 'D5',
            'p': 'D#5',
            ';': 'E5'
        };

        // 预设曲目
        const songs = {
            twinkle: [{
                note: 'C4',
                duration: 400
            }, {
                note: 'C4',
                duration: 400
            }, {
                note: 'G4',
                duration: 400
            }, {
                note: 'G4',
                duration: 400
            }, {
                note: 'A4',
                duration: 400
            }, {
                note: 'A4',
                duration: 400
            }, {
                note: 'G4',
                duration: 800
            }, {
                note: 'F4',
                duration: 400
            }, {
                note: 'F4',
                duration: 400
            }, {
                note: 'E4',
                duration: 400
            }, {
                note: 'E4',
                duration: 400
            }, {
                note: 'D4',
                duration: 400
            }, {
                note: 'D4',
                duration: 400
            }, {
                note: 'C4',
                duration: 800
            }],
            birthday: [{
                note: 'C4',
                duration: 300
            }, {
                note: 'C4',
                duration: 200
            }, {
                note: 'D4',
                duration: 500
            }, {
                note: 'C4',
                duration: 500
            }, {
                note: 'F4',
                duration: 500
            }, {
                note: 'E4',
                duration: 1000
            }, {
                note: 'C4',
                duration: 300
            }, {
                note: 'C4',
                duration: 200
            }, {
                note: 'D4',
                duration: 500
            }, {
                note: 'C4',
                duration: 500
            }, {
                note: 'G4',
                duration: 500
            }, {
                note: 'F4',
                duration: 1000
            }],
            jingle: [{
                note: 'E4',
                duration: 400
            }, {
                note: 'E4',
                duration: 400
            }, {
                note: 'E4',
                duration: 800
            }, {
                note: 'E4',
                duration: 400
            }, {
                note: 'E4',
                duration: 400
            }, {
                note: 'E4',
                duration: 800
            }, {
                note: 'E4',
                duration: 400
            }, {
                note: 'G4',
                duration: 400
            }, {
                note: 'C4',
                duration: 400
            }, {
                note: 'D4',
                duration: 400
            }, {
                note: 'E4',
                duration: 1200
            }],
            ode: [{
                note: 'E4',
                duration: 400
            }, {
                note: 'E4',
                duration: 400
            }, {
                note: 'F4',
                duration: 400
            }, {
                note: 'G4',
                duration: 400
            }, {
                note: 'G4',
                duration: 400
            }, {
                note: 'F4',
                duration: 400
            }, {
                note: 'E4',
                duration: 400
            }, {
                note: 'D4',
                duration: 400
            }, {
                note: 'C4',
                duration: 400
            }, {
                note: 'C4',
                duration: 400
            }, {
                note: 'D4',
                duration: 400
            }, {
                note: 'E4',
                duration: 400
            }, {
                note: 'E4',
                duration: 600
            }, {
                note: 'D4',
                duration: 200
            }, {
                note: 'D4',
                duration: 800
            }]
        };

        // 录制相关
        let isRecording = false;
        let recordedNotes = [];
        let recordStartTime = 0;

        // 生成钢琴键
        function createPiano() {
            const container = document.getElementById('keysContainer');
            const whiteNotes = ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5', 'D5', 'E5'];
            const blackNotes = ['C#4', 'D#4', null, 'F#4', 'G#4', 'A#4', null, 'C#5', 'D#5'];
            const keyLabels = ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';'];
            const blackKeyLabels = ['W', 'E', null, 'T', 'Y', 'U', null, 'O', 'P'];

            // 创建白键
            whiteNotes.forEach((note, index) => {
                const key = document.createElement('div');
                key.className = 'white-key';
                key.dataset.note = note;

                const noteName = document.createElement('div');
                noteName.className = 'note-name';
                noteName.textContent = note;
                key.appendChild(noteName);

                const label = document.createElement('div');
                label.className = 'key-label';
                label.textContent = keyLabels[index];
                key.appendChild(label);

                key.addEventListener('mousedown', () => playNote(note, key));
                key.addEventListener('mouseup', () => stopNote(key));
                key.addEventListener('mouseleave', () => stopNote(key));

                container.appendChild(key);
            });

            // 创建黑键
            blackNotes.forEach((note, index) => {
                if (note) {
                    const key = document.createElement('div');
                    key.className = 'black-key';
                    key.dataset.note = note;
                    key.style.left = `${(index + 1) * 64 - 20}px`;

                    const noteName = document.createElement('div');
                    noteName.className = 'note-name';
                    noteName.textContent = note;
                    key.appendChild(noteName);

                    const label = document.createElement('div');
                    label.className = 'key-label';
                    label.textContent = blackKeyLabels[index];
                    key.appendChild(label);

                    key.addEventListener('mousedown', () => playNote(note, key));
                    key.addEventListener('mouseup', () => stopNote(key));
                    key.addEventListener('mouseleave', () => stopNote(key));

                    container.appendChild(key);
                }
            });
        }

        // 播放音符
        function playNote(note, keyElement) {
            if (!noteFrequencies[note]) return;

            const oscillator = audioContext.createOscillator();
            const gainNode = audioContext.createGain();

            oscillator.connect(gainNode);
            gainNode.connect(audioContext.destination);

            oscillator.frequency.value = noteFrequencies[note];
            oscillator.type = 'sine';

            gainNode.gain.setValueAtTime(0, audioContext.currentTime);
            gainNode.gain.linearRampToValueAtTime(masterVolume * 0.3, audioContext.currentTime + 0.01);

            oscillator.start(audioContext.currentTime);

            if (keyElement) {
                keyElement.classList.add('active');
                keyElement.oscillator = oscillator;
                keyElement.gainNode = gainNode;
            }

            // 录制
            if (isRecording) {
                recordedNotes.push({
                    note: note,
                    time: Date.now() - recordStartTime
                });
            }

            return {
                oscillator,
                gainNode
            };
        }

        // 停止音符
        function stopNote(keyElement) {
            if (keyElement && keyElement.oscillator) {
                keyElement.gainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 0.1);
                keyElement.oscillator.stop(audioContext.currentTime + 0.1);
                keyElement.classList.remove('active');
                keyElement.oscillator = null;
                keyElement.gainNode = null;
            }
        }

        // 播放曲目
        let currentSongTimeout = null;
        async function playSong(songNotes) {
            stopSong();

            for (let i = 0; i < songNotes.length; i++) {
                const {
                    note,
                    duration
                } = songNotes[i];
                const keyElement = document.querySelector(`[data-note="${note}"]`);

                const {
                    oscillator,
                    gainNode
                } = playNote(note, keyElement);

                await new Promise(resolve => {
                    currentSongTimeout = setTimeout(() => {
                        gainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 0.1);
                        oscillator.stop(audioContext.currentTime + 0.1);
                        if (keyElement) keyElement.classList.remove('active');
                        resolve();
                    }, duration);
                });

                await new Promise(resolve => {
                    currentSongTimeout = setTimeout(resolve, 100);
                });
            }
        }

        // 停止播放
        function stopSong() {
            if (currentSongTimeout) {
                clearTimeout(currentSongTimeout);
                currentSongTimeout = null;
            }
            document.querySelectorAll('.white-key, .black-key').forEach(key => {
                stopNote(key);
            });
        }

        // 键盘事件
        const pressedKeys = new Set();
        document.addEventListener('keydown', (e) => {
            const key = e.key.toLowerCase();
            if (keyboardMap[key] && !pressedKeys.has(key)) {
                pressedKeys.add(key);
                const note = keyboardMap[key];
                const keyElement = document.querySelector(`[data-note="${note}"]`);
                playNote(note, keyElement);
            }
        });

        document.addEventListener('keyup', (e) => {
            const key = e.key.toLowerCase();
            if (keyboardMap[key]) {
                pressedKeys.delete(key);
                const note = keyboardMap[key];
                const keyElement = document.querySelector(`[data-note="${note}"]`);
                stopNote(keyElement);
            }
        });

        // 控制按钮
        document.getElementById('playBtn').addEventListener('click', () => {
            const songName = document.getElementById('songSelect').value;
            if (songName && songs[songName]) {
                playSong(songs[songName]);
            }
        });

        document.getElementById('stopBtn').addEventListener('click', stopSong);

        document.getElementById('recordBtn').addEventListener('click', () => {
            const btn = document.getElementById('recordBtn');
            const indicator = document.getElementById('recordingIndicator');
            const playbackBtn = document.getElementById('playbackBtn');

            if (!isRecording) {
                isRecording = true;
                recordedNotes = [];
                recordStartTime = Date.now();
                btn.textContent = '⏹ 停止录制';
                indicator.classList.add('active');
                playbackBtn.disabled = true;
            } else {
                isRecording = false;
                btn.textContent = '⏺ 录制';
                indicator.classList.remove('active');
                if (recordedNotes.length > 0) {
                    playbackBtn.disabled = false;
                }
            }
        });

        document.getElementById('playbackBtn').addEventListener('click', async() => {
            if (recordedNotes.length === 0) return;

            for (let i = 0; i < recordedNotes.length; i++) {
                const {
                    note,
                    time
                } = recordedNotes[i];
                const nextTime = i < recordedNotes.length - 1 ? recordedNotes[i + 1].time : time + 500;
                const duration = nextTime - time;

                const keyElement = document.querySelector(`[data-note="${note}"]`);
                const {
                    oscillator,
                    gainNode
                } = playNote(note, keyElement);

                await new Promise(resolve => {
                    setTimeout(() => {
                        gainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 0.1);
                        oscillator.stop(audioContext.currentTime + 0.1);
                        if (keyElement) keyElement.classList.remove('active');
                        resolve();
                    }, Math.min(duration, 500));
                });
            }
        });

        // 音量控制
        const volumeSlider = document.getElementById('volumeSlider');
        const volumeValue = document.getElementById('volumeValue');

        volumeSlider.addEventListener('input', (e) => {
            masterVolume = e.target.value / 100;
            volumeValue.textContent = e.target.value + '%';
        });

        // 初始化
        createPiano();
    </script>
</body>

</html>